package com.example.zluserservice.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.example.zluserservice.client.RoleFeignClient;
import com.example.zluserservice.client.UserRoleFeignClient;
import com.example.zluserservice.common.annotation.OperationLog;
import com.example.zluserservice.common.base.PageResponse;
import com.example.zluserservice.common.base.ResponseResult;
import com.example.zluserservice.common.constant.CommonConstant;
import com.example.zluserservice.common.constant.UserCacheConstant;
import com.example.zluserservice.common.exception.BaseException;
import com.example.zluserservice.common.util.IpUtil;
import com.example.zluserservice.common.util.UserThreadLocal;
import com.example.zluserservice.dto.request.UserReqDTO;
import com.example.zluserservice.dto.response.RoleResDTO;
import com.example.zluserservice.dto.response.UserResDTO;
import com.example.zluserservice.entity.User;
import com.example.zluserservice.entity.UserRole;
import com.example.zluserservice.framework.mq.message.OperationLogMessage;
import com.example.zluserservice.framework.mq.producer.OperationLogProducer;
import com.example.zluserservice.framework.properties.SecurityConfigProperties;
import com.example.zluserservice.mapper.IUserMapper;
import com.example.zluserservice.service.IUserService;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import io.seata.spring.annotation.GlobalTransactional;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.Date;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * @Author zhenliu（孙凌岳）
 * @Description 实现系统用户service
 * @Date 2025/6/14 12:09
 * @Version 1.0
 */
@Service
@Slf4j
public class IUserServiceImpl extends ServiceImpl<IUserMapper, User> implements IUserService {
    @Resource
    private StringRedisTemplate stringRedisTemplate;

    @Resource
    private IUserMapper userMapper;

    @Resource
    private RoleFeignClient roleFeignClient;

    @Resource
    private UserRoleFeignClient userRoleFeignClient;

    @Resource
    private BCryptPasswordEncoder bCryptPasswordEncoder;

    @Resource
    private SecurityConfigProperties securityConfigProperties;

    /**
     * 分页查询用户
     * @param userReqDTO 查询条件
     * @param pageNum 页码
     * @param pageSize 每页条数
     * @return
     */
    @Override
    public PageResponse<UserResDTO> findUserPage(UserReqDTO userReqDTO, int pageNum, int pageSize) {
        /**
         * 初始版本分页查询
         */
//        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
//        if (ObjectUtil.isNotEmpty(userReqDTO.getNickName())) {
//            queryWrapper.like("role_name", userReqDTO.getNickName());
//        }
//
//        if (ObjectUtil.isNotEmpty(userReqDTO.getEmail())) {
//            queryWrapper.eq("label", userReqDTO.getEmail());
//        }
//
//        if (ObjectUtil.isNotEmpty(userReqDTO.getDataState())) {
//            queryWrapper.eq("data_state", userReqDTO.getDataState());
//        }
//
//        //降序排列
//        queryWrapper.orderByDesc("create_time");
//
//        //构造分页对象
//        Page<User> page = new Page<>(pageNum, pageSize);
//        //查询信息
//        userMapper.selectPage(page, queryWrapper);
//        //封装信息
//        PageResponse<UserResDTO> pageResponse = PageResponse.of(page,UserResDTO.class);

        /**
         * 实现数据权限控制的分页查询
         */
        Page<User> page = new Page<>(pageNum, pageSize);

        //设置分页参数到参数对象中
        IPage<User> userPage = userMapper.selectUserPage(page, userReqDTO);

        //封装响应
        PageResponse<UserResDTO> pageResponse = PageResponse.of(userPage, UserResDTO.class);


        //如果有数据则进行角色装配
        if (!CollUtil.isEmpty(pageResponse.getRecords())){
            List<Long> userIds = pageResponse.getRecords().stream().map(UserResDTO::getId).collect(Collectors.toList());
            //查询对应角色
            List<RoleResDTO> roleResDTOList = roleFeignClient.findRoleResDTOListInUserId(userIds);

            //装配数据
            pageResponse.getRecords().forEach(n->{
                //装配角色
                Set<String> roleVoIds = Sets.newHashSet();
                //
                Set<String> roleVoLabels = Sets.newHashSet();
                roleResDTOList.forEach(r->{
                    if (String.valueOf(n.getId()).equals(r.getUserId())){
                        roleVoIds.add(String.valueOf(r.getId()));
                        roleVoLabels.add(r.getRoleName());

                    }
                });
                n.setRoleLabels(roleVoLabels);
                n.setRoleVoIds(roleVoIds);
            });
        }
        return pageResponse;
    }

    /**
     * 用户登录 - 根据姓名获取用户信息
     * @param username
     * @return
     */
    @Override
    public UserResDTO findUserResDTOForLogin(String username) {
        UserResDTO userResDTO = UserResDTO.builder()
                .username(username)
                .dataState(CommonConstant.DATA_STATE_0)
                .build();
        User user = lambdaQuery()
                .eq(ObjectUtil.isNotNull(userResDTO.getUsername()), User::getUsername, userResDTO.getUsername())
                .eq(ObjectUtil.isNotNull(userResDTO.getDataState()), User::getDataState, userResDTO.getDataState())
                .one();
        if(!ObjectUtil.isNull(user)){
            UserResDTO userResDTORet = BeanUtil.toBean(user, UserResDTO.class);
            return userResDTORet;
        }
        throw new RuntimeException("用户名或密码错误");
    }

    /**
     * 用户新增
     * @param userReqDTO
     * @return
     */
    @Override
    @OperationLog(action = "create_user",detail = "新增用户")
    public UserResDTO createUser(UserReqDTO userReqDTO) {
        //生成基于redis自增策略的自定义ID
        Long userId = generatorUserId();
        //转换UserVo为User
        User user = BeanUtil.toBean(userReqDTO, User.class);
        //设置生成的ID
        user.setId(userId);
        user.setCreateBy(UserThreadLocal.getMgtUserId());
        user.setUpdateBy(UserThreadLocal.getMgtUserId());
        user.setUsername(user.getEmail());
        user.setNickName(user.getNickName());
        user.setCreateBy(UserThreadLocal.getMgtUserId());
        user.setUpdateBy(UserThreadLocal.getMgtUserId());

//        log.info(securityConfigProperties.getDefaultPassword());
        String password = bCryptPasswordEncoder.encode(securityConfigProperties.getDefaultPassword());
        user.setPassword(password);

        int flag = userMapper.insert(user);
        if (flag == 0) {
            throw new RuntimeException("保存用户信息出错");
        }

        //rpc调用权限服务保存用户角色中间表
        //组装数据
        List<UserRole> userRoles = Lists.newArrayList();
        userReqDTO.getRoleVoIds().forEach(r -> {
            userRoles.add(UserRole.builder()
                    .userId(userId)
                    .roleId(Long.valueOf(r))
                    .dataState(CommonConstant.DATA_STATE_0)
                    .createTime(LocalDateTime.now())
                    .updateTime(LocalDateTime.now())
                    .createBy(UserThreadLocal.getMgtUserId())
                    .build());
        });

        //rpc调用
        flag = userRoleFeignClient.batchInsert(userRoles);
        if (flag == 0) {
            throw new RuntimeException("rpc调用保存用户角色中间表出错");
        }

        return BeanUtil.toBean(user, UserResDTO.class);
    }

    /**
     * 修改用户
     * @param userReqDTO
     * @return
     */
    @Override
    @GlobalTransactional   // 分布式事务问题
    @OperationLog(action = "update_user",detail = "修改用户信息")
    public Boolean updateUser(UserReqDTO userReqDTO) {
        //转换UserVo为User
        User user = BeanUtil.toBean(userReqDTO, User.class);

        boolean update = lambdaUpdate()
                .set(user.getUsername() != null, User::getUsername, user.getUsername())
                .set(user.getPassword() != null, User::getPassword, user.getPassword())
                .set(user.getAvatar() != null, User::getAvatar, user.getAvatar())
                .set(user.getNickName() != null, User::getNickName, user.getNickName())
                .set(user.getEmail() != null, User::getEmail, user.getEmail())
                .set(user.getMobile() != null, User::getMobile, user.getMobile())
                .set(user.getSex() != null, User::getSex, user.getSex())
                .set(user.getDataState() != null, User::getDataState, user.getDataState())
                .set(user.getUpdateTime() != null, User::getUpdateTime, user.getUpdateTime())
                .set(user.getRemark() != null, User::getRemark, user.getRemark())
                .set(user.getCreateBy() != null, User::getCreateBy, user.getCreateBy())
                .set(user.getUpdateBy() != null, User::getUpdateBy, user.getUpdateBy())
                .eq(User::getId, user.getId()).update();

        if (!update) {
            throw new RuntimeException("修改用户信息出错");
        }

        if (CollUtil.isNotEmpty(userReqDTO.getRoleVoIds())) {
            //删除角色中间表
            boolean flagDel = userRoleFeignClient.deleteUserRoleByUserId(user.getId());
            if (!flagDel) {
                throw new RuntimeException("删除角色中间表出错");
            }

            //重新保存角色中间表
            List<UserRole> userRoles = Lists.newArrayList();
            userReqDTO.getRoleVoIds().forEach(r -> {
                userRoles.add(UserRole.builder()
                        .userId(user.getId())
                        .roleId(Long.valueOf(r))
                        .dataState(CommonConstant.DATA_STATE_0)
                        .createTime(LocalDateTime.now())
                        .updateTime(LocalDateTime.now())
                        .createBy(UserThreadLocal.getMgtUserId())
                        .build());
            });
            int flag = userRoleFeignClient.batchInsert(userRoles);

//                /**
//                 * 测试分布式事务
//                 */
//                int i = 1 / 0;

            if (flag == 0) {
                throw new RuntimeException("保存角色中间表出错");
            }
        }

        return true;
    }

    /**
     * 根据id删除用户
     *
     * @param userId
     * @return
     */
    @Override
    @OperationLog(action = "delete_user",detail = "删除用户")
    public Integer deleteUserById(Long userId) {
        // 删除用户与角色关联
        userRoleFeignClient.deleteUserRoleByUserId(userId);

        //删除用户信息
        int delete = userMapper.deleteById(userId);

        if (delete == 0) {
            throw new BaseException("删除用户失败");
        }

        return delete;
    }

    /**
     * 重置密码
     * @param userId
     * @return
     */
    @Override
    @OperationLog(action = "reset_password",detail = "重置密码")
    public Boolean resetPasswords(Long userId) {
        String password = bCryptPasswordEncoder.encode(securityConfigProperties.getDefaultPassword());

        boolean update = lambdaUpdate()
                .eq(User::getId, userId)
                .set(User::getPassword, password)
                .update();

        return update;
    }


    /**
     * 通过Redis自增序列得到序号
     */
    private Long generatorUserId() {
        //通过Redis自增序列得到序号
        Long id = stringRedisTemplate.opsForValue().increment(UserCacheConstant.USERS_SHARD_KEY_ID_GENERATOR, 1);
        Long orderId = 1000000L + id;
        return orderId;
    }

    /**
     * 测试用户添加和生成id
     * @param user
     */
    @Override
    public void testAdd(User user) {
        user.setId(generatorUserId());
        userMapper.insert(user);
    }
}